package com.hanxiaozhang.aspect;

import com.hanxiaozhang.annotation.LogAnnotation;
import com.hanxiaozhang.api.fegin.base.BaseFeignClient;
import com.hanxiaozhang.base.entity.LogEntity;
import com.hanxiaozhang.constant.DelFlagEnum;
import com.hanxiaozhang.security.CurrentUserUtil;
import com.hanxiaozhang.util.HttpContextUtil;
import com.hanxiaozhang.util.IpUtil;
import com.hanxiaozhang.util.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;


/**
 * 功能描述: <br>
 * 〈保存系统日志〉
 * <p>
 *
 * @Author:hanxiaozhang
 * @Date: 2021/3/19
 */
@Slf4j
@Aspect
@Component
public class LogAspect {

    @Autowired
    private BaseFeignClient baseFeignClient;

    /**
     * 最大长度
     */
    @Value("${hanxiaozhang.log.max.length:5000}")
    private int maxLength;


    @Pointcut("@annotation(com.hanxiaozhang.annotation.LogAnnotation)")
    public void logPointCut() {
    }

    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        // 执行方法
        Object result = point.proceed();
        // 执行时长(毫秒)
        long time = System.currentTimeMillis() - beginTime;
        //异步保存日志
        saveLog(point, time);
        return result;
    }

    /**
     * 保存日志
     *
     * @param joinPoint
     * @param time
     */
    void saveLog(ProceedingJoinPoint joinPoint, long time)  {

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        LogEntity logEntity = LogEntity.builder()
                .userId(CurrentUserUtil.getUserId())
                .username(CurrentUserUtil.getUserName())
                .time(time)
                .build();
        logEntity.setCreateBy(CurrentUserUtil.getUserName())
                .setCreateDate(LocalDateTime.now())
                .setDelFlag(DelFlagEnum.NORMAL.getCode());
        // 请求的方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = className + "." + signature.getName() + "()";
        logEntity.setMethod(methodName);
        // 操作和模块名称
        LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);
        if (logAnnotation != null) {
            String operation = logAnnotation.operation();
            String moduleName = logAnnotation.moduleName().getModuleName();
            logEntity.setOperation(operation).setModuleName(moduleName);
        }
        // 请求的参数
        String params = objectToString(joinPoint.getArgs());
        logEntity.setParams(params);
        // ip
        HttpServletRequest request = HttpContextUtil.getHttpServletRequest();
        String ip = IpUtil.getIp(request);
        logEntity.setIp(ip);
        baseFeignClient.save(logEntity);
    }


    /**
     * 将对象转为字符串作为log输出
     *
     * @param obj
     * @return 字符串
     */
    private String objectToString(Object obj) {
        // 对象为空
        if (obj == null) {
            return "";
        }
        // 对象为枚举类
        if (obj instanceof Enum) {
            return obj.toString();
        }
        try {
            String json = JsonUtil.beanToJson(obj);
            if (json.length() > maxLength) {
                return json.substring(0, maxLength) + "...";
            }
            return json;
        } catch (Exception e) {
            log.warn(e.getMessage());
            return obj.toString();
        }
    }

}
